package com.example.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.api.entity.biz.User;
import com.example.api.entity.order.OrderInfo;
import com.example.api.exception.CommonRuntimeException;
import com.example.api.vo.biz.UserVo;
import com.example.feign.order.OrderService;
import com.example.mapper.UserMapper;
import com.example.service.ThreadPoolExecutorService;
import com.example.service.UserService;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import utils.BeanUtils;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * @Author Story
 * @Date 2022/3/19 23:21
 * @Version 1.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final UserMapper userMapper;
    private final OrderService orderService;
    private final ThreadPoolExecutorService threadPoolExecutorService;

    @Override
    public UserVo load(String id) {
        User user = userMapper.selectById(id);
        return BeanUtil.isEmpty(user) ? null : BeanUtils.toBean(user, UserVo.class);
    }

    @Override
    public User login(String userName, String password) {
        User user = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUserId, userName).eq(User::getPassword, password));
        if (BeanUtil.isEmpty(user)) {
            throw new CommonRuntimeException("账号密码错误，登陆失败");
        }
        return user;
    }

    @Override
    public UserVo addUser(UserVo userVo) {
        Optional.of(userVo).orElseThrow(() -> new CommonRuntimeException("空值异常"));
        User user1 = BeanUtils.toBean(userVo, User.class);
        if (StrUtil.isNotBlank(user1.getId())) {
            this.userMapper.updateUser(user1);
        } else {
            user1.insert();
        }
        try {
            List<OrderInfo> orderlist = orderService.getOrderlist();
        } catch (Exception e) {
            log.error(JSONUtil.toJsonStr(e.getMessage()));
            graceRetry(userVo);
        }
        return BeanUtils.toBean(user1, UserVo.class);
    }

    /**
     * RPC调用重试机制
     *
     * @return
     */
    public UserVo graceRetry(UserVo userVo) {
        log.debug("进入重试机制=============");
        Retryer<UserVo> retryer = RetryerBuilder.<UserVo>newBuilder()
                .retryIfException()        // 当发生异常时重试
                .retryIfResult(response -> BeanUtil.isEmpty(userVo))
                .withWaitStrategy(WaitStrategies.fibonacciWait(10, Long.MAX_VALUE, TimeUnit.MILLISECONDS))    // 等待策略
                .withStopStrategy(StopStrategies.stopAfterAttempt(5))        // 重试达到5次时退出
                .build();
        try {
            return retryer.call(new Callable<UserVo>() {
                @Override
                public UserVo call() throws Exception {
                    log.info("重试调用");
                    return this.call();
                }
            });
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        throw new RuntimeException("重试失败");
    }
}
